#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Matplotlib 3D绘图示例
演示三维数据可视化技术
"""

import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.patches as patches

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False

def basic_3d_plots():
    """基础3D图形示例"""
    print("=== 基础3D图形示例 ===")
    
    fig = plt.figure(figsize=(15, 10))
    
    # 子图1: 3D线图
    ax1 = fig.add_subplot(2, 3, 1, projection='3d')
    t = np.linspace(0, 4*np.pi, 100)
    x = np.sin(t)
    y = np.cos(t)
    z = t
    ax1.plot(x, y, z, label='螺旋线')
    ax1.set_xlabel('X轴')
    ax1.set_ylabel('Y轴')
    ax1.set_zlabel('Z轴')
    ax1.set_title('3D线图')
    ax1.legend()
    
    # 子图2: 3D散点图
    ax2 = fig.add_subplot(2, 3, 2, projection='3d')
    np.random.seed(42)
    n = 100
    x = np.random.randn(n)
    y = np.random.randn(n)
    z = np.random.randn(n)
    colors = np.random.rand(n)
    
    scatter = ax2.scatter(x, y, z, c=colors, cmap='viridis', s=50)
    ax2.set_xlabel('X轴')
    ax2.set_ylabel('Y轴')
    ax2.set_zlabel('Z轴')
    ax2.set_title('3D散点图')
    plt.colorbar(scatter, ax=ax2, shrink=0.5)
    
    # 子图3: 3D柱状图
    ax3 = fig.add_subplot(2, 3, 3, projection='3d')
    xpos = np.arange(5)
    ypos = np.arange(4)
    xposM, yposM = np.meshgrid(xpos, ypos)
    
    xpos = xposM.ravel()
    ypos = yposM.ravel()
    zpos = np.zeros_like(xpos)
    
    dx = dy = 0.8
    dz = np.random.rand(len(xpos)) * 10
    
    ax3.bar3d(xpos, ypos, zpos, dx, dy, dz, alpha=0.8)
    ax3.set_xlabel('X轴')
    ax3.set_ylabel('Y轴')
    ax3.set_zlabel('Z轴')
    ax3.set_title('3D柱状图')
    
    # 子图4: 参数化曲线
    ax4 = fig.add_subplot(2, 3, 4, projection='3d')
    u = np.linspace(0, 2*np.pi, 100)
    x = np.cos(u)
    y = np.sin(u)
    z = u/(2*np.pi)
    
    ax4.plot(x, y, z, 'r-', linewidth=3)
    ax4.plot(x, y, 0, 'b--', alpha=0.5)  # 投影到底面
    ax4.set_xlabel('X轴')
    ax4.set_ylabel('Y轴')
    ax4.set_zlabel('Z轴')
    ax4.set_title('参数化曲线')
    
    # 子图5: 3D线框图
    ax5 = fig.add_subplot(2, 3, 5, projection='3d')
    x = np.linspace(-2, 2, 10)
    y = np.linspace(-2, 2, 10)
    X, Y = np.meshgrid(x, y)
    Z = X**2 + Y**2
    
    ax5.plot_wireframe(X, Y, Z, alpha=0.7)
    ax5.set_xlabel('X轴')
    ax5.set_ylabel('Y轴')
    ax5.set_zlabel('Z轴')
    ax5.set_title('3D线框图')
    
    # 子图6: 多条3D曲线
    ax6 = fig.add_subplot(2, 3, 6, projection='3d')
    t = np.linspace(0, 2*np.pi, 100)
    
    for i in range(5):
        x = np.cos(t + i*np.pi/4)
        y = np.sin(t + i*np.pi/4)
        z = i * np.ones_like(t)
        ax6.plot(x, y, z, label=f'层{i+1}')
    
    ax6.set_xlabel('X轴')
    ax6.set_ylabel('Y轴')
    ax6.set_zlabel('Z轴')
    ax6.set_title('多层螺旋')
    ax6.legend()
    
    plt.tight_layout()
    plt.show()

def surface_plots():
    """3D表面图示例"""
    print("=== 3D表面图示例 ===")
    
    fig = plt.figure(figsize=(15, 10))
    
    # 创建网格数据
    x = np.linspace(-3, 3, 50)
    y = np.linspace(-3, 3, 50)
    X, Y = np.meshgrid(x, y)
    
    # 子图1: 基本表面图
    ax1 = fig.add_subplot(2, 3, 1, projection='3d')
    Z1 = np.sin(np.sqrt(X**2 + Y**2))
    surf1 = ax1.plot_surface(X, Y, Z1, cmap='viridis', alpha=0.8)
    ax1.set_title('基本表面图')
    ax1.set_xlabel('X轴')
    ax1.set_ylabel('Y轴')
    ax1.set_zlabel('Z轴')
    fig.colorbar(surf1, ax=ax1, shrink=0.5)
    
    # 子图2: 高斯分布表面
    ax2 = fig.add_subplot(2, 3, 2, projection='3d')
    Z2 = np.exp(-(X**2 + Y**2)/2)
    surf2 = ax2.plot_surface(X, Y, Z2, cmap='coolwarm', alpha=0.8)
    ax2.set_title('高斯分布表面')
    ax2.set_xlabel('X轴')
    ax2.set_ylabel('Y轴')
    ax2.set_zlabel('Z轴')
    fig.colorbar(surf2, ax=ax2, shrink=0.5)
    
    # 子图3: 鞍形表面
    ax3 = fig.add_subplot(2, 3, 3, projection='3d')
    Z3 = X**2 - Y**2
    surf3 = ax3.plot_surface(X, Y, Z3, cmap='plasma', alpha=0.8)
    ax3.set_title('鞍形表面')
    ax3.set_xlabel('X轴')
    ax3.set_ylabel('Y轴')
    ax3.set_zlabel('Z轴')
    fig.colorbar(surf3, ax=ax3, shrink=0.5)
    
    # 子图4: 波浪表面
    ax4 = fig.add_subplot(2, 3, 4, projection='3d')
    Z4 = np.sin(X) * np.cos(Y)
    surf4 = ax4.plot_surface(X, Y, Z4, cmap='RdYlBu', alpha=0.8)
    ax4.set_title('波浪表面')
    ax4.set_xlabel('X轴')
    ax4.set_ylabel('Y轴')
    ax4.set_zlabel('Z轴')
    fig.colorbar(surf4, ax=ax4, shrink=0.5)
    
    # 子图5: 球面
    ax5 = fig.add_subplot(2, 3, 5, projection='3d')
    u = np.linspace(0, 2*np.pi, 30)
    v = np.linspace(0, np.pi, 20)
    u, v = np.meshgrid(u, v)
    x_sphere = np.cos(u) * np.sin(v)
    y_sphere = np.sin(u) * np.sin(v)
    z_sphere = np.cos(v)
    
    surf5 = ax5.plot_surface(x_sphere, y_sphere, z_sphere, 
                            cmap='viridis', alpha=0.8)
    ax5.set_title('球面')
    ax5.set_xlabel('X轴')
    ax5.set_ylabel('Y轴')
    ax5.set_zlabel('Z轴')
    
    # 子图6: 复杂函数表面
    ax6 = fig.add_subplot(2, 3, 6, projection='3d')
    Z6 = np.sin(X) * np.exp(-0.1*(X**2 + Y**2))
    surf6 = ax6.plot_surface(X, Y, Z6, cmap='hot', alpha=0.8)
    ax6.set_title('衰减振荡表面')
    ax6.set_xlabel('X轴')
    ax6.set_ylabel('Y轴')
    ax6.set_zlabel('Z轴')
    fig.colorbar(surf6, ax=ax6, shrink=0.5)
    
    plt.tight_layout()
    plt.show()

def contour_3d_examples():
    """3D等高线图示例"""
    print("=== 3D等高线图示例 ===")
    
    fig = plt.figure(figsize=(15, 10))
    
    # 创建数据
    x = np.linspace(-3, 3, 100)
    y = np.linspace(-3, 3, 100)
    X, Y = np.meshgrid(x, y)
    Z = np.sin(np.sqrt(X**2 + Y**2))
    
    # 子图1: 3D等高线
    ax1 = fig.add_subplot(2, 3, 1, projection='3d')
    ax1.contour(X, Y, Z, levels=10, cmap='viridis')
    ax1.set_title('3D等高线')
    ax1.set_xlabel('X轴')
    ax1.set_ylabel('Y轴')
    ax1.set_zlabel('Z轴')
    
    # 子图2: 填充3D等高线
    ax2 = fig.add_subplot(2, 3, 2, projection='3d')
    ax2.contourf(X, Y, Z, levels=15, cmap='plasma', alpha=0.8)
    ax2.set_title('填充3D等高线')
    ax2.set_xlabel('X轴')
    ax2.set_ylabel('Y轴')
    ax2.set_zlabel('Z轴')
    
    # 子图3: 组合表面和等高线
    ax3 = fig.add_subplot(2, 3, 3, projection='3d')
    surf = ax3.plot_surface(X, Y, Z, alpha=0.6, cmap='coolwarm')
    ax3.contour(X, Y, Z, levels=10, colors='black', linewidths=1, alpha=0.8)
    ax3.set_title('表面+等高线')
    ax3.set_xlabel('X轴')
    ax3.set_ylabel('Y轴')
    ax3.set_zlabel('Z轴')
    
    # 子图4: 投影等高线
    ax4 = fig.add_subplot(2, 3, 4, projection='3d')
    ax4.plot_surface(X, Y, Z, alpha=0.5, cmap='viridis')
    # 在底面投影等高线
    ax4.contour(X, Y, Z, zdir='z', offset=Z.min(), cmap='viridis')
    # 在侧面投影等高线
    ax4.contour(X, Y, Z, zdir='x', offset=X.min(), cmap='viridis')
    ax4.contour(X, Y, Z, zdir='y', offset=Y.max(), cmap='viridis')
    ax4.set_title('投影等高线')
    ax4.set_xlabel('X轴')
    ax4.set_ylabel('Y轴')
    ax4.set_zlabel('Z轴')
    
    # 子图5: 多层等高线
    ax5 = fig.add_subplot(2, 3, 5, projection='3d')
    Z_levels = np.linspace(Z.min(), Z.max(), 5)
    for i, level in enumerate(Z_levels):
        ax5.contour(X, Y, Z, levels=[level], colors=plt.cm.viridis(i/4))
    ax5.set_title('多层等高线')
    ax5.set_xlabel('X轴')
    ax5.set_ylabel('Y轴')
    ax5.set_zlabel('Z轴')
    
    # 子图6: 三维等高线切片
    ax6 = fig.add_subplot(2, 3, 6, projection='3d')
    # 在不同Z层画等高线
    for z_level in np.linspace(-0.5, 0.5, 6):
        ax6.contour(X, Y, Z, levels=[z_level], zdir='z', 
                   offset=z_level, cmap='plasma')
    ax6.set_title('等高线切片')
    ax6.set_xlabel('X轴')
    ax6.set_ylabel('Y轴')
    ax6.set_zlabel('Z轴')
    ax6.set_zlim(-1, 1)
    
    plt.tight_layout()
    plt.show()

def parametric_3d_plots():
    """参数化3D图形示例"""
    print("=== 参数化3D图形示例 ===")
    
    fig = plt.figure(figsize=(15, 10))
    
    # 子图1: 环面 (Torus)
    ax1 = fig.add_subplot(2, 3, 1, projection='3d')
    u = np.linspace(0, 2*np.pi, 30)
    v = np.linspace(0, 2*np.pi, 30)
    u, v = np.meshgrid(u, v)
    
    R, r = 3, 1  # 大半径和小半径
    x_torus = (R + r*np.cos(v)) * np.cos(u)
    y_torus = (R + r*np.cos(v)) * np.sin(u)
    z_torus = r * np.sin(v)
    
    ax1.plot_surface(x_torus, y_torus, z_torus, alpha=0.8, cmap='viridis')
    ax1.set_title('环面')
    ax1.set_xlabel('X轴')
    ax1.set_ylabel('Y轴')
    ax1.set_zlabel('Z轴')
    
    # 子图2: 莫比乌斯带
    ax2 = fig.add_subplot(2, 3, 2, projection='3d')
    u = np.linspace(0, 2*np.pi, 30)
    v = np.linspace(-0.5, 0.5, 10)
    u, v = np.meshgrid(u, v)
    
    x_mobius = (1 + v*np.cos(u/2)) * np.cos(u)
    y_mobius = (1 + v*np.cos(u/2)) * np.sin(u)
    z_mobius = v * np.sin(u/2)
    
    ax2.plot_surface(x_mobius, y_mobius, z_mobius, alpha=0.8, cmap='plasma')
    ax2.set_title('莫比乌斯带')
    ax2.set_xlabel('X轴')
    ax2.set_ylabel('Y轴')
    ax2.set_zlabel('Z轴')
    
    # 子图3: 旋转抛物面
    ax3 = fig.add_subplot(2, 3, 3, projection='3d')
    u = np.linspace(-2, 2, 30)
    v = np.linspace(0, 2*np.pi, 30)
    u, v = np.meshgrid(u, v)
    
    x_para = u * np.cos(v)
    y_para = u * np.sin(v)
    z_para = u**2
    
    ax3.plot_surface(x_para, y_para, z_para, alpha=0.8, cmap='coolwarm')
    ax3.set_title('旋转抛物面')
    ax3.set_xlabel('X轴')
    ax3.set_ylabel('Y轴')
    ax3.set_zlabel('Z轴')
    
    # 子图4: 双曲抛物面
    ax4 = fig.add_subplot(2, 3, 4, projection='3d')
    u = np.linspace(-2, 2, 30)
    v = np.linspace(-2, 2, 30)
    u, v = np.meshgrid(u, v)
    
    x_hyp = u
    y_hyp = v
    z_hyp = u**2 - v**2
    
    ax4.plot_surface(x_hyp, y_hyp, z_hyp, alpha=0.8, cmap='RdYlBu')
    ax4.set_title('双曲抛物面')
    ax4.set_xlabel('X轴')
    ax4.set_ylabel('Y轴')
    ax4.set_zlabel('Z轴')
    
    # 子图5: 螺旋面
    ax5 = fig.add_subplot(2, 3, 5, projection='3d')
    u = np.linspace(0, 4*np.pi, 50)
    v = np.linspace(-1, 1, 20)
    u, v = np.meshgrid(u, v)
    
    x_helix = v * np.cos(u)
    y_helix = v * np.sin(u)
    z_helix = u
    
    ax5.plot_surface(x_helix, y_helix, z_helix, alpha=0.8, cmap='hot')
    ax5.set_title('螺旋面')
    ax5.set_xlabel('X轴')
    ax5.set_ylabel('Y轴')
    ax5.set_zlabel('Z轴')
    
    # 子图6: 克莱因瓶的一部分
    ax6 = fig.add_subplot(2, 3, 6, projection='3d')
    u = np.linspace(0, 2*np.pi, 30)
    v = np.linspace(0, 2*np.pi, 30)
    u, v = np.meshgrid(u, v)
    
    x_klein = (2 + np.cos(v/2)*np.sin(u) - np.sin(v/2)*np.sin(2*u)) * np.cos(v)
    y_klein = (2 + np.cos(v/2)*np.sin(u) - np.sin(v/2)*np.sin(2*u)) * np.sin(v)
    z_klein = np.sin(v/2)*np.sin(u) + np.cos(v/2)*np.sin(2*u)
    
    ax6.plot_surface(x_klein, y_klein, z_klein, alpha=0.8, cmap='viridis')
    ax6.set_title('克莱因瓶')
    ax6.set_xlabel('X轴')
    ax6.set_ylabel('Y轴')
    ax6.set_zlabel('Z轴')
    
    plt.tight_layout()
    plt.show()

def animated_3d_example():
    """3D动画示例"""
    print("=== 3D动画示例 ===")
    
    from matplotlib.animation import FuncAnimation
    
    # 创建图形和3D子图
    fig = plt.figure(figsize=(10, 8))
    ax = fig.add_subplot(111, projection='3d')
    
    # 创建初始数据
    t = np.linspace(0, 2*np.pi, 100)
    x = np.sin(t)
    y = np.cos(t)
    z = t
    
    # 初始化线对象
    line, = ax.plot(x, y, z, 'b-', linewidth=3)
    
    # 设置坐标轴
    ax.set_xlim(-2, 2)
    ax.set_ylim(-2, 2)
    ax.set_zlim(0, 2*np.pi)
    ax.set_xlabel('X轴')
    ax.set_ylabel('Y轴')
    ax.set_zlabel('Z轴')
    ax.set_title('旋转的3D螺旋线')
    
    def animate(frame):
        """动画函数"""
        # 旋转视角
        ax.view_init(elev=30, azim=frame*2)
        return line,
    
    # 创建动画
    ani = FuncAnimation(fig, animate, frames=180, interval=50, blit=False)
    
    plt.show()
    
    # 注意：这里只是演示代码，实际运行时会显示动画
    print("动画演示：3D图形会自动旋转")

def interactive_3d_example():
    """交互式3D图形示例"""
    print("=== 交互式3D图形示例 ===")
    
    fig = plt.figure(figsize=(12, 8))
    
    # 创建数据
    x = np.linspace(-5, 5, 50)
    y = np.linspace(-5, 5, 50)
    X, Y = np.meshgrid(x, y)
    Z = np.sin(np.sqrt(X**2 + Y**2))
    
    # 子图1: 可交互的表面图
    ax1 = fig.add_subplot(1, 2, 1, projection='3d')
    surf1 = ax1.plot_surface(X, Y, Z, cmap='viridis', alpha=0.8)
    ax1.set_title('可交互表面图\n(可以用鼠标旋转)')
    ax1.set_xlabel('X轴')
    ax1.set_ylabel('Y轴')
    ax1.set_zlabel('Z轴')
    
    # 子图2: 带等高线的表面图
    ax2 = fig.add_subplot(1, 2, 2, projection='3d')
    surf2 = ax2.plot_surface(X, Y, Z, alpha=0.6, cmap='coolwarm')
    ax2.contour(X, Y, Z, zdir='z', offset=Z.min(), cmap='coolwarm')
    ax2.set_title('表面图+底部等高线')
    ax2.set_xlabel('X轴')
    ax2.set_ylabel('Y轴')
    ax2.set_zlabel('Z轴')
    
    plt.tight_layout()
    plt.show()
    
    print("提示：可以用鼠标拖拽来旋转3D图形")
    print("      可以用滚轮来缩放")

def main():
    """主函数，运行所有3D绘图示例"""
    print("Matplotlib 3D绘图演示")
    print("=" * 50)
    
    basic_3d_plots()
    surface_plots()
    contour_3d_examples()
    parametric_3d_plots()
    interactive_3d_example()
    
    # 注意：动画示例需要特殊处理，在某些环境下可能无法正常显示
    try:
        animated_3d_example()
    except Exception as e:
        print(f"动画示例跳过: {e}")
    
    print("\n3D绘图演示完成！")
    print("3D绘图适用于：")
    print("- 科学数据的三维可视化")
    print("- 工程建模和设计")
    print("- 数学函数的几何表示")
    print("- 统计数据的多维展示")
    print("- 物理现象的空间分布")

if __name__ == "__main__":
    main() 